{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-01-06T07:10:17.389768Z",
     "start_time": "2021-01-06T07:10:17.379639Z"
    }
   },
   "source": [
    "# Quantum Approximate Optimization Algorithm\n",
    "\n",
    "<em> Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved. </em>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Overview\n",
    "\n",
    "Quantum Approximate Optimization Algorithm (QAOA) is a quantum algorithm that can run on recent Noisy Intermediate-Scale Quantum (NISQ) devices and has a wide range of applications. QAOA was proposed by Edward Farhi et al. in 2014 [1], and its purpose is to solve combinatorial optimization problems approximately."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Combinatorial optimization problem\n",
    "\n",
    "In applied mathematics and theoretical computer science, combinatorial optimization is a type of topic that finds the optimal object in a discrete set of objects. In simple terms, the combinatorial optimization problem means that all solutions of the problem are composed of discrete variables, and the optimal solution is to be found in the discrete solution set. Combinatorial optimization problems involve a wide range of areas and are common in real life, such as the design of aircraft routes and the planning of express delivery routes.\n",
    "\n",
    "Specifically, a combinatorial optimization problem can be described by $n$ bits and $m$ clauses. Each bit is a binary variable whose value is $0$ or $1$, and we use $z_j$ to denote the value of the $j$th bit. Therefore, the value of these $n$ bits can be represented by the bit string $z=z_1z_2\\dots z_n$. Each clause is a restriction on some bits. For example, a clause can require the value of the $2$nd bit to be $0$, or it can require the value of the $3$rd bit and the $5$th bit to be the same. For the $j$th clause, we define a function\n",
    "\n",
    "$$\n",
    "C_j(z)=\n",
    "\\begin{cases}\n",
    "1 & \\text{If the value $z$ of $n$ bits satisfies the condition indicated by clause $j$}\\\\\n",
    "0 & \\text{if the value $z$ of $n$ bits does not satisfy the condition indicated by clause $j$}\n",
    "\\end{cases}.\n",
    "\\tag{1}\n",
    "$$\n",
    "\n",
    "For example, if the first clause requires the value of the second bit to be 0, then we have $C_1(z_10z_3\\dots z_n)=1$ and $C_1(z_11z_3\\dots z_n)=0$.\n",
    "\n",
    "From the definition of $C_j$ in equation (1), we can define the objective function of the combinatorial optimization problem\n",
    "\n",
    "$$\n",
    "C(z)=\\sum_{j=1}^m w_jC_j(z),\n",
    "\\tag{2}\n",
    "$$\n",
    "\n",
    "where $w_j$ is the weight of the $j$th clause. The combinatorial optimization problem is to find a value $z$ that maximizes the value of the objective function $C(z)$, namely\n",
    "\n",
    "$$\n",
    "\\underset{z}{\\operatorname{argmax}} C(z).\n",
    "\\tag{3}\n",
    "$$\n",
    "\n",
    "In theoretical computer science, there is a famous problem called the Boolean satisfiability problem (SAT). This problem asks that, given $n$ bits and $m$ clauses as inputs, if there exists a value these bits can take so that all the $m$ clauses are satisfied simultaneously. An optimization problem related to SAT is MAX-SAT, which asks that what value these $n$ bits should take so that as many as possible clauses are satisfied. It is worth noting that the way we define a combinatorial optimization problem above is to formulate it as MAX-SAT, or more precisely, weighted MAX-SAT."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Quantum approximate optimization algorithm\n",
    "\n",
    "Many combinatorial optimization problems are NP-complete or even NP-hard problems, which means that computers may not be able to solve such problems efficiently. An alternative is to find the approximate optimal solution to such problems, and this task can usually be completed efficiently. QAOA is a quantum algorithm that can find an approximate optimal solution to a combinatorial optimization problem.\n",
    "\n",
    "### Encoding combinatorial optimization problem\n",
    "\n",
    "For the above combinatorial optimization problem, there are $n$ bits and $m$ clauses. The QAOA algorithm transforms this problem into an optimization problem on an $n$-qubit system. Each computational basis state $|z\\rangle \\in \\{0,1\\}^n$ of the quantum system corresponds to a value $z$ of $n$ bits in the original problem. At the same time, for the $j$th clause in the original problem, we define a diagonal Hamiltonian $H_{C_j}$ satisfying\n",
    "\n",
    "$$\n",
    "H_{C_j}|z\\rangle = C_j(z)|z\\rangle.\n",
    "\\tag{4}\n",
    "$$\n",
    "\n",
    "Specifically, we can construct the Hamiltonian $H_{C_j}$ through the following equation:\n",
    "\n",
    "$$\n",
    "H_{C_j} = \\sum_{z\\in\\{0,1\\}^n} C_j(z)|z\\rangle\\langle z|.\n",
    "\\tag{5}\n",
    "$$\n",
    "\n",
    "For example, assuming that $z^{(1)}$ and $z^{(2)}$ are the values ​​satisfying the $j$th clause, then we can define\n",
    "\n",
    "$$\n",
    "H_{C_j} = |z^{(1)}\\rangle\\langle z^{(1)}| + |z^{(2)}\\rangle\\langle z^{(2)}|.\n",
    "\\tag{6}\n",
    "$$\n",
    "\n",
    "Therefore, QAOA encodes the objective function $C$ of the combinatorial optimization problem into the Hamiltonian $H_C$ on a system with $n$ qubits, where\n",
    "\n",
    "$$\n",
    "H_C = \\sum_{j=1}^m w_jH_{C_j},\n",
    "\\tag{7}\n",
    "$$\n",
    "\n",
    "and\n",
    "\n",
    "$$\n",
    "H_C|z\\rangle = \\sum_{j=1}^m w_jH_{C_j}|z\\rangle = \\sum_{j=1}^m w_jC_j(z)|z\\rangle = C(z)|z\\rangle .\n",
    "\\tag{8}\n",
    "$$\n",
    "\n",
    "It is worth noting that if an optimal solution to the original problem is $z_\\text{opt}$, then we have\n",
    "\n",
    "$$\n",
    "\\langle z_\\text{opt}|H_C|z_\\text{opt}\\rangle = \\langle z_\\text{opt}|C(z_\\text{opt})|z_\\text{opt}\\rangle = C( z_\\text{opt})\\langle z_\\text{opt}|z_\\text{opt}\\rangle = C(z_\\text{opt}).\n",
    "\\tag{9}\n",
    "$$\n",
    "\n",
    "Therefore, an optimal solution of the original combinatorial optimization problem is an eigenstate with the largest eigenvalue of the Hamiltonian $H_C$. In addition, for any quantum state $|\\psi\\rangle$,\n",
    "\n",
    "$$\n",
    "\\langle\\psi|H_C|\\psi\\rangle \\leq C(z_\\text{opt}),\n",
    "\\tag{10}\n",
    "$$\n",
    "\n",
    "and the equation takes the equal sign if and only if $|\\psi\\rangle$ is a superposition state of optimal solutions. It can be obtained from equation (9) and equation (10) that\n",
    "\n",
    "$$\n",
    "\\max_{|\\psi\\rangle} \\langle\\psi|H_C|\\psi\\rangle = C(z_\\text{opt}),\n",
    "\\tag{11}\n",
    "$$\n",
    "\n",
    "and finding the optimal solution of the original combinatorial optimization problem is equivalent to finding an eigenstate with the largest eigenvalue of the Hamiltonian $H_C$, that is, finding a quantum state $|\\psi\\rangle$ such that\n",
    "\n",
    "$$\n",
    "H_C|\\psi\\rangle = C(z_\\text{opt})|\\psi\\rangle.\n",
    "\\tag{12}\n",
    "$$\n",
    "\n",
    "When we find such a quantum state $|\\psi\\rangle$, it is probably not a computational basis state, but a superposition of several computational basis states, each of which is an optimal solution of the original combinatorial optimization problem. Therefore, we can obtain an optimal solution to the original combinatorial optimization problem by performing computational basis measurements on $|\\psi\\rangle$.\n",
    "\n",
    "### Finding an approximate optimal solution\n",
    "\n",
    "Although it is relatively simple to encode the objective function of the combinatorial optimization problem to be solved into the Hamiltonian $H_C$ of a quantum system, finding the quantum state $|\\psi\\rangle$ representing an optimal solution from the huge Hilbert space according to equation (11) is not easy. In order to find such a quantum state, we need another Hamiltonian\n",
    "\n",
    "$$\n",
    "H_B = \\sum_{j=1}^n X_j,\n",
    "\\tag{13}\n",
    "$$\n",
    "\n",
    "where $X_j$ represents the Pauli $X$ gate acting on the $j$th qubit. The two eigenstates of Pauli $X$ gate are $|+\\rangle$ and $|-\\rangle$, and their corresponding eigenvalues ​​are $1$ and $-1$, respectively:\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "X|+\\rangle &=\n",
    "\\begin{bmatrix}\n",
    "0&1\\\\1&0\n",
    "\\end{bmatrix}\n",
    "\\frac{1}{\\sqrt{2}}\n",
    "\\begin{bmatrix}\n",
    "1\\\\1\n",
    "\\end{bmatrix}\n",
    "= \\frac{1}{\\sqrt{2}}\n",
    "\\begin{bmatrix}\n",
    "1\\\\1\n",
    "\\end{bmatrix}\n",
    "= |+\\rangle,\\tag{14}\\\\\n",
    "X|-\\rangle &=\n",
    "\\begin{bmatrix}\n",
    "0&1\\\\1&0\n",
    "\\end{bmatrix}\n",
    "\\frac{1}{\\sqrt{2}}\n",
    "\\begin{bmatrix}\n",
    "1\\\\-1\n",
    "\\end{bmatrix}\n",
    "= \\frac{1}{\\sqrt{2}}\n",
    "\\begin{bmatrix}\n",
    "-1\\\\1\n",
    "\\end{bmatrix}\n",
    "= -|-\\rangle.\\tag{15}\n",
    "\\end{align}\n",
    "$$\n",
    "\n",
    "Therefore, the eigenstate with the largest eigenvalue of $H_B$ is\n",
    "\n",
    "$$\n",
    "|s\\rangle \\equiv \\underbrace{|+\\rangle\\otimes\\cdots\\otimes|+\\rangle}_\\text{$n$ terms} = |+\\rangle^{\\otimes n }.\n",
    "\\tag{16}\n",
    "$$\n",
    "\n",
    "We will use this quantum state $|s\\rangle$ as the initial state for the algorithm. After constructing the Hamiltonian $H_C$ and $H_B$, we can start to find an approximate optimal solution to the original combinatorial optimization problem. According to the Hamiltonian $H_C$ and $H_B$, respectively define the unitary transformation\n",
    "\n",
    "$$\n",
    "U_C(\\gamma) = e^{-i\\gamma H_C}\n",
    "\\tag{17}\n",
    "$$\n",
    "\n",
    "and unitary transformation\n",
    "\n",
    "$$\n",
    "U_B(\\beta) = e^{-i\\beta H_B},\n",
    "\\tag{18}\n",
    "$$\n",
    "\n",
    "where $\\gamma$ and $\\beta$ are adjustable real parameters. Given any integer $p\\geq1$ and the parameters $\\vec{\\gamma}=(\\gamma_1,\\dots,\\gamma_p)$ and $\\vec{\\beta}=(\\beta_1,\\dots,\\beta_p) $, we define\n",
    "\n",
    "$$\n",
    "|\\vec{\\gamma},\\vec{\\beta}\\rangle = U_B(\\beta_p)U_C(\\gamma_p)\\cdots U_B(\\beta_1)U_C(\\gamma_1)|s\\rangle.\n",
    "\\tag{19}\n",
    "$$\n",
    "\n",
    "It can be seen that the integer $p$ represents the number of layers of $U_C, U_B$, that is, the $U_C$ and $U_B$ are alternately applied to the initial state $|s\\rangle$ $p$ times. Let us denote $F_p(\\vec{\\gamma},\\vec{\\beta})$ as the expected value of the Hamiltonian $H_C$ in the quantum state of equation (19):\n",
    "\n",
    "$$\n",
    "F_p(\\vec{\\gamma},\\vec{\\beta}) = \\langle\\vec{\\gamma},\\vec{\\beta}|H_C|\\vec{\\gamma},\\vec{\\beta}\\rangle .\n",
    "\\tag{20}\n",
    "$$\n",
    "\n",
    "By adjusting the parameters $\\vec{\\gamma},\\vec{\\beta}$, we can get\n",
    "\n",
    "$$\n",
    "M_p = \\max_{\\vec{\\gamma},\\vec{\\beta}} F_p(\\vec{\\gamma},\\vec{\\beta})\n",
    "\\tag{21}\n",
    "$$\n",
    "\n",
    "as the approximate optimal solution under a given number of layers $p$. So far, we have transformed the problem of searching for the quantum state $|\\psi\\rangle$ into a problem of searching for the parameters $\\vec{\\gamma},\\vec{\\beta}$. It is worth noting that the search space given by $p$ layers of $U_C, U_B$ is larger than that of $p-1$ layers, so\n",
    "\n",
    "$$\n",
    "M_p \\geq M_{p-1}.\n",
    "\\tag{22}\n",
    "$$\n",
    "\n",
    "In fact, when $p$ is large enough,\n",
    "\n",
    "$$\n",
    "\\lim_{p\\to\\infty} M_p = \\max_z C(z).\n",
    "\\tag{23}\n",
    "$$\n",
    "\n",
    "### Decoding the quantum solution\n",
    "\n",
    "In the previous paragraph, we simplify the search for the quantum state $|\\psi\\rangle$ into the search for the parameterized quantum state $|\\vec{\\gamma},\\vec{\\beta}\\rangle$, but at the same time, we have also reduced the search space. That is to say, given the number of layers $p$, there may be no parameters $\\vec{\\gamma},\\vec{\\beta}$ such that $F_p(\\vec{\\gamma},\\vec{\\beta}) = C(z_\\text{opt})$. Suppose that the parameters $\\vec{\\gamma}^*$ and $\\vec{\\beta}^*$ make $F_p$ the largest, that is, $F_p(\\vec{\\gamma}^*,\\vec{\\beta}^* ) = M_p$. Then under ideal circumstances, the quantum state $|\\vec{\\gamma}^*,\\vec{\\beta}^*\\rangle$ contains the information of an optimal solution. But it should be noted that only $p$ layers are used here, so it is very likely that $M_p < C(z_\\text{opt})$. Therefore, in general $|\\vec{\\gamma}^*,\\vec{\\beta}^*\\rangle$ only contains information about an approximate optimal solution. Furthermore, we assume that the quantum state $|\\vec{\\gamma}^*,\\vec{\\beta}^*\\rangle$ is the superposition state of $l$ computational basis state, namely\n",
    "\n",
    "$$\n",
    "|\\vec{\\gamma}^*,\\vec{\\beta}^*\\rangle = c_1|z^{(1)}\\rangle + \\cdots + c_l|z^{(l)}\\rangle.\n",
    "\\tag{24}\n",
    "$$\n",
    "\n",
    "Normally, the larger the probability $|c_j|^2$ that a state $|z^{(j)}\\rangle$ is measured on the computational basis, the more likely that the corresponding bit string $z^{(j) }$ is an optimal solution. Thus, we prepare $|\\vec{\\gamma}^*,\\vec{\\beta}^*\\rangle$ and measure it to get a bit string $z$ and calculate the value of $C(z)$. Repeat this process many times, and we can get a bit string $z$ that makes $C(z)$ close to or even exceed $M_p$.\n",
    "\n",
    "### Adiabatic theorem\n",
    "\n",
    "Why do we use the above method to construct the quantum state $|\\vec{\\gamma},\\vec{\\beta}\\rangle$? QAOA tries to find an approximate optimal solution to an optimization problem. A similar algorithm is the quantum adiabatic algorithm [2] (QAA). The difference is that QAA is designed to find an optimal solution to the optimization problem rather than an approximate one. Similar to QAOA, QAA transforms an optimization problem into a problem of finding the ground state of a Hamiltonian, and uses the adiabatic theorem to solve it. Consider the Hamiltonian\n",
    "\n",
    "$$\n",
    "H(t) = (1-\\frac tT)H_B + \\frac tT H_C,\n",
    "\\tag{25}\n",
    "$$\n",
    "\n",
    "of a quantum system. At initial, time $t=0$, and the Hamiltonian of the system is $H(0) = H_B$. As time passes, the Hamiltonian of the system gradually changes from $H_B$ to $H_C$. When $t=T$, the Hamiltonian of the system becomes $H(T) = H_C$. The adiabatic theorem in quantum mechanics tells us that if the system is in an eigenstate of $H_B$ at the beginning, then as long as the evolution time $T$ is long enough, the system will be in the eigenstate of the corresponding energy level of $H_C$ when the Hamiltonian of the system completely evolves to $H_C$. Therefore, if the system is initially in $|s\\rangle$, that is, the eigenstate with the largest eigenvalue of $H_B$, after a sufficiently long evolution time $T$, the quantum state of the system will become the eigenstate with the largest eigenvalue of $H_C$. [3]\n",
    "\n",
    "One way to simulate the evolution of the Hamiltonian $H(t)$ over time $t$ is to alternately apply the unitary transformations $U_C(\\gamma)$ and $U_B(\\beta)$ on the quantum system, and the accuracy of simulation depends on the value of $\\gamma,\\beta$. In addition, in order for the evolution of the system to follow the adiabatic theorem, a sufficiently long evolution time is required, so the value of $p$ is required to be large enough. Therefore, combining equation (22) we can deduce the conclusion in equation (23)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "_______\n",
    "\n",
    "## References\n",
    "\n",
    "[1] Farhi, E., Goldstone, J. & Gutmann, S. A Quantum Approximate Optimization Algorithm. [arXiv:1411.4028 (2014).](https://arxiv.org/abs/1411.4028)\n",
    "\n",
    "[2] Farhi, E., Goldstone, J., Gutmann, S. & Sipser, M. Quantum computation by adiabatic evolution. [arXiv:quant-ph/0001106 (2000).](https://arxiv.org/abs/quant-ph/0001106)\n",
    "\n",
    "[3] Duan, R. Quantum Adiabatic Theorem Revisited. [arXiv:2003.03063 (2020).](https://arxiv.org/abs/2003.03063)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "426.667px"
   },
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
